#include "Emitter.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include <iterator>
#include "Entity.h"
#include "GamePlayState.h"
#include "Enemy.h"
#include "Game.h"
#include "Player.h"
#include "Shadowmancer.h"

void Emitter::Init()
{
	for (int i = 0; i < NumParticles; i++)
	{
		dead.push_back(new Particle);
	}
	if (alive.size())
	{
		std::list<Particle*>::iterator iter = alive.begin();
		for (; iter!=alive.end(); )
		{
			delete *iter;
			iter = alive.erase(iter);
		}
	}
	waited = 0;
	count = 0;
}

Emitter::~Emitter()
{
	std::list<Particle*>::iterator iter;
	if (alive.size())
	{
		for (iter = alive.begin(); iter != alive.end(); iter++)
		{
			delete *iter;
		}
	}
	if (dead.size())
	{
		for (iter = dead.begin(); iter != dead.end(); iter++)
		{
			delete *iter;
		}
	}
	owner = nullptr;
}

void Emitter::Update(float dt)
{
	float x = Game::GetInstance()->GetCameraPos().x;
	float y = Game::GetInstance()->GetCameraPos().y;
	//make particle pointers
	if (owner)
	{
		Position = owner->GetRect().ComputeCenter();
	}
	std::list<Particle*>::iterator iter;
	for (iter = alive.begin(); iter != alive.end();)
	{
		(*iter)->LifeCurr += dt;
		if ((*iter)->LifeCurr >= (*iter)->LifeEnd)
		{
			if (looping)
			{
				dead.push_front(*iter);
				iter = alive.erase(iter);
			}
			else
			{
				delete *iter;
				iter = alive.erase(iter);
			}
			continue;
		}
		if (gravity)
		{
			SGD::Vector diff = gravpos - (*iter)->Position;
			diff.Normalize();
			diff *= gravpull;
			(*iter)->VelocityCurr += diff*dt;
			(*iter)->Position += (*iter)->VelocityCurr*dt;
		}
		else if (bursting)
		{
			(*iter)->Position += (*iter)->VelocityCurr*dt;
		}
		else
		{
			(*iter)->VelocityCurr.x += Flyweight.VelocityChange.x*dt;
			(*iter)->VelocityCurr.y += Flyweight.VelocityChange.y*dt;
			(*iter)->Position += (*iter)->VelocityCurr*dt;
		}
		(*iter)->RotaionCurr += Flyweight.RotationChange*dt;
		(*iter)->ScaleCurr.width += Flyweight.ScaleChange.width*dt;
		(*iter)->ScaleCurr.height += Flyweight.ScaleChange.height*dt;
		(*iter)->ColorCurr.alpha = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndA - Flyweight.ColorStartA) + Flyweight.ColorStartA));
		(*iter)->ColorCurr.red =   unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndR - Flyweight.ColorStartR) + Flyweight.ColorStartR));
		(*iter)->ColorCurr.green = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndG - Flyweight.ColorStartG) + Flyweight.ColorStartG));
		(*iter)->ColorCurr.blue =  unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndB - Flyweight.ColorStartB) + Flyweight.ColorStartB));
		++iter;
	}
	waited += dt;
	while (waited >= SpawnRate && (int)alive.size() < NumParticles)
	{
		if (!looping)
			count++;
		Particle*back;
		if (dead.size() != 0)
		{
			back = dead.back();
			dead.pop_back();
		}
		else
			return;
		//alive.addHead(n);

		switch (EmitterShape)
		{
		case Rect:
		{
			SGD::Rectangle temp{ Position, Size };
			float x = Position.x + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Position.x + Size.width) - Position.x)));
			float y = Position.y + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Position.y + Size.height) - Position.y)));
			back->Position = { x, y };
		}
			break;
		case Circle:
		{
			SGD::Rectangle temp{ Position, Size };
			float x;
			float y;
			while (true)
			{
				x = (Position.x - Spread) + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Position.x + Spread) - (Position.x - Spread))));
				y = (Position.y - Spread) + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Position.y + Spread) - (Position.y - Spread))));
				//float h = sqrt(pow(x - Position.x, 2) + pow(y - Position.y, 2));
				SGD::Vector vet;
				SGD::Point ran{ x, y };
				vet = ran - Position;
				if (vet.ComputeLength() <= Spread)
				{
					back->Position = { x, y };
					break;
				}
			}
		}
			break;
		case Line:
		{
			float x;
			x = Position.x - Spread + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Position.x + Spread) - (Position.x - Spread))));
			back->Position = { x, Position.y };
		}
			break;
		case Point:

			break;
		}
		if (bursting)
		{
			float x = Flyweight.VelocityChange.x + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Flyweight.VelocityStart.x) - Flyweight.VelocityChange.x)));
			float y = Flyweight.VelocityChange.y + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / ((Flyweight.VelocityStart.y) - Flyweight.VelocityChange.y)));
			back->setPart(Flyweight.MinLife, Flyweight.MaxLife, SGD::Color{ Flyweight.ColorStartA, Flyweight.ColorStartR, Flyweight.ColorStartG, Flyweight.ColorStartB }
			, Flyweight.RotationStart, Flyweight.ScaleStart, { x, y });
			back->Position = Position;
		}
		else
		{
			back->setPart(Flyweight.MinLife, Flyweight.MaxLife, SGD::Color{ Flyweight.ColorStartA, Flyweight.ColorStartR, Flyweight.ColorStartG, Flyweight.ColorStartB }
			, Flyweight.RotationStart, Flyweight.ScaleStart, Flyweight.VelocityStart);
			back->Position = Position;
			SGD::Vector up;
			if (owner->GetType() == Entity::ENT_ENEMY  &&dynamic_cast<Enemy*>(owner)->GetEType() == EType::shike)
			{
				up = owner->GetRect().ComputeCenter() - dynamic_cast<Enemy*>(owner)->GetCurrentPlanet()->GetRect().ComputeCenter();
				Flyweight.VelocityChange.x = up.x;
				Flyweight.VelocityChange.y = up.y;
			}
			else
				up = back->Position - owner->GetRect().ComputeCenter();
			up.Normalize();
			back->VelocityCurr.x = up.x;
			back->VelocityCurr.y = up.y;
		}
		alive.push_back(back);
		waited -= SpawnRate;
	}
	if (count >= NumParticles&&!looping&&alive.size() == 0)
		complete = true;
}

void Emitter::ShadowUpdate(int type, Entity*howner, float dt,Emitter*hook)
{
	std::list<Particle*>::iterator iter;
	//anchorpoint
	if (type == 0)
	{
		if (hook)
		{
			gravpos = hook->Position;
			SGD::Vector angle;
			angle = this->Position - hook->Position; 
			gravpull = fabs(angle.ComputeLength()*10);
		}
		for (iter = alive.begin(); iter != alive.end();)
		{
			(*iter)->LifeCurr += dt;
			if ((*iter)->LifeCurr >= (*iter)->LifeEnd)
			{
				dead.push_front(*iter);
				iter = alive.erase(iter);
			}
			SGD::Vector diff = gravpos - (*iter)->Position;
			diff.Normalize();
			diff *= gravpull;
			(*iter)->VelocityCurr += diff*dt;
			(*iter)->Position += (*iter)->VelocityCurr*dt;
			(*iter)->RotaionCurr += Flyweight.RotationChange*dt;
			(*iter)->ScaleCurr.width += Flyweight.ScaleChange.width*dt;
			(*iter)->ScaleCurr.height += Flyweight.ScaleChange.height*dt;
			(*iter)->ColorCurr.alpha = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndA - Flyweight.ColorStartA) + Flyweight.ColorStartA));
			(*iter)->ColorCurr.red =   unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndR - Flyweight.ColorStartR) + Flyweight.ColorStartR));
			(*iter)->ColorCurr.green = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndG - Flyweight.ColorStartG) + Flyweight.ColorStartG));
			(*iter)->ColorCurr.blue =  unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndB - Flyweight.ColorStartB) + Flyweight.ColorStartB));
			++iter;
		}
		waited += dt;
		while (waited >= SpawnRate && (int)alive.size() < NumParticles)
		{
			Particle*back;
			if (dead.size() != 0)
			{
				back = dead.back();
				dead.pop_back();
			}
			back->setPart(Flyweight.MinLife, Flyweight.MaxLife, SGD::Color{ Flyweight.ColorStartA, Flyweight.ColorStartR, Flyweight.ColorStartG, Flyweight.ColorStartB }
			, Flyweight.RotationStart, Flyweight.ScaleStart, Flyweight.VelocityStart);
			back->Position = Position;
			SGD::Vector angle;
			angle = this->Position - hook->Position;
			SGD::Vector up = { 0, -1 };
			float ang = angle.ComputeAngle(up);
			up = angle.ComputeRotated(SGD::PI / 2);
			//up.Rotate(ang);
			up.Normalize();
			float x=0;
			if (howner->GetType() == Entity::ENT_PLAYER && dynamic_cast<Player*>(howner)->GetDestinationPlanet())
				x = dynamic_cast<Player*>(howner)->GetDestinationPlanet()->GetRadius();
			back->VelocityCurr.x = up.x*x;
			back->VelocityCurr.y = up.y*x;

			alive.push_back(back);
			waited -= SpawnRate;
		}
	}
	//line
	else
	{
		for (iter = alive.begin(); iter != alive.end();)
		{
			(*iter)->LifeCurr += dt;
			if ((*iter)->LifeCurr >= (*iter)->LifeEnd)
			{
				dead.push_front(*iter);
				iter = alive.erase(iter);
			}
			(*iter)->Position += (*iter)->VelocityCurr*dt;
			(*iter)->RotaionCurr += Flyweight.RotationChange*dt;
			(*iter)->ScaleCurr.width += Flyweight.ScaleChange.width*dt;
			(*iter)->ScaleCurr.height += Flyweight.ScaleChange.height*dt;
			(*iter)->ColorCurr.alpha = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndA - Flyweight.ColorStartA) + Flyweight.ColorStartA));
			(*iter)->ColorCurr.red =   unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndR - Flyweight.ColorStartR) + Flyweight.ColorStartR));
			(*iter)->ColorCurr.green = unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndG - Flyweight.ColorStartG) + Flyweight.ColorStartG));
			(*iter)->ColorCurr.blue =  unsigned char((((*iter)->LifeCurr / (*iter)->LifeEnd) * (Flyweight.ColorEndB - Flyweight.ColorStartB) + Flyweight.ColorStartB));
			++iter;
		}
		waited += dt;
		while (waited >= SpawnRate && (int)alive.size() < NumParticles)
		{
			Particle*back;
			if (dead.size() != 0)
			{
				back = dead.back();
				dead.pop_back();
			}
			SGD::Vector dis = howner->GetRect().ComputeCenter() - Position ;
			float dist = dis.ComputeLength();
			dis.Normalize();
			//dist /= 2;
			float x;
			std::random_device rd; //create the random device seed
			std::mt19937 mt(rd()); //create the random engine and seed it with the device
			std::uniform_real_distribution<float> randRadius(0, dist);
			x = randRadius(mt);
			back->Position = Position + (dis*x);

			back->setPart(Flyweight.MinLife, Flyweight.MaxLife, SGD::Color{ Flyweight.ColorStartA, Flyweight.ColorStartR, Flyweight.ColorStartG, Flyweight.ColorStartB }
			, Flyweight.RotationStart, Flyweight.ScaleStart, Flyweight.VelocityStart);


			alive.push_back(back);
			waited -= SpawnRate;
		}
	}
}

void Emitter::Render()
{
	SGD::GraphicsManager*graph = SGD::GraphicsManager::GetInstance();
	SGD::Point offset;
	std::list<Particle*>::iterator iter = alive.begin();
	for (; iter != alive.end(); ++iter)
	{
		offset.x = ((*iter)->Position.x - Game::GetInstance()->GetCameraPos().x -(64 * ((*iter)->ScaleCurr.width))) * Game::GetInstance()->GetZoomLevel();
		offset.y = ((*iter)->Position.y - Game::GetInstance()->GetCameraPos().y -(64 * ((*iter)->ScaleCurr.height))) * Game::GetInstance()->GetZoomLevel();
		graph->DrawTexture(Flyweight.image, offset,
			(*iter)->RotaionCurr, { 64, 64 }, (*iter)->ColorCurr, (*iter)->ScaleCurr*Game::GetInstance()->GetZoomLevel());
	}
}